package jsave.services;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;

import jsave.conf.Configuration;
import jsave.conf.Options;
import jsave.exception.JSaveException;
import jsave.filter.JSaveJTreeFilter;
import jsave.tree.FileNode;
import jsave.tree.JSaveTree;

import org.apache.log4j.Logger;

import algutil.date.ConversionDate;
import algutil.fichier.ConversionFichier;
import algutil.filter.DirectoryFilter;

public class JSaveServices {

	private static final Logger log = Logger.getLogger(JSaveServices.class);

	private static JSaveServices services = null;

	private JSaveServices() {
	}

	public static JSaveServices getInstance() {
		if (services == null) {
			services = new JSaveServices();
		}
		return services;
	}

	/**
	 * @deprecated use mirror2incremental.bat script
	 */
	public void transformerMirrorToIncrementalDestination(File d)
			throws IOException {
		// rename d d_date-heure
		// mkdir d
		// move d_date-heure d
		// + creer iniFile incremental

		// String path = d.getPath();

		Runtime runtime = Runtime.getRuntime();
		/*
		 * Process process = runtime.exec("rename " + d.getPath() + " " +
		 * d.getPath() + "_2022920"); log.info(process);
		 */
		d.renameTo(new File(d.getParent() + File.separator + "test2_2022920"));
		d.mkdir();
		String dPath = d.getPath();

		Process process = runtime.exec("move " + dPath + "_2022920 " + dPath
				+ "");
		log.info(process);
	}

	public boolean isMirrorSaveDestination(File d) throws JSaveException,
			IOException {
		return (getSaveTypeDestination(d) == Configuration.MIRROR_SAVE) ? true
				: false;
	}

	public boolean isIncrementalSaveDestination(File d) throws JSaveException,
			IOException {
		return (getSaveTypeDestination(d) == Configuration.INCREMENTAL_SAVE) ? true
				: false;
	}

	public int getSaveTypeDestination(File d) throws JSaveException,
			IOException {

		if (!d.exists()) {
			throw new JSaveException(
					"Le repertoire destination n'existe pas : " + d.getPath());
		}

		// recherche du .jsave
		ResourceBundle iniFile = getIniFileAsResourceBundle(d);
		if (iniFile == null) {
			return Configuration.UNKNOW;
		} else {
			String typeSave;
			try {
				typeSave = iniFile.getString("type_save");
			} catch (Exception e) {
				log
						.debug("Impossible de trouver la propriete 'type_save' dans le fichier properties '"
								+ d.getPath() + "'");
				typeSave = null;
			}
			if (typeSave == null) {
				return Configuration.UNKNOW;
			} else {
				typeSave = typeSave.trim();
				if (typeSave.equalsIgnoreCase("MIRROR")) {
					return Configuration.MIRROR_SAVE;
				} else if (typeSave.equalsIgnoreCase("INCREMENTAL")) {
					return Configuration.INCREMENTAL_SAVE;
				} else {
					return Configuration.UNKNOW;
				}
			}
		}
	}

	public File getIniFile(File d) {
		File iniFile = new File(d.getPath() + File.separator + ".jsave");
		if (!iniFile.exists()) {
			return null;
		}
		return iniFile;
	}

	public ResourceBundle getIniFileAsResourceBundle(File d) throws IOException {
		File iniFile = new File(d.getPath());
		if (!iniFile.exists()) {
			return null;
		}
		ResourceBundle myResources = null;
		FileInputStream istream = new FileInputStream(iniFile);
		myResources = new PropertyResourceBundle(istream);
		istream.close();
		return myResources;
	}

	public long getLastSaveDatetime(File repDest) throws IOException {
		ResourceBundle rb = getIniFileAsResourceBundle(getIniFile(repDest));
		long datetime = Long.parseLong(rb.getString("last_save_in_millis"));
		return datetime;
	}

	public static void main(String[] args) throws IOException {
		getInstance().transformerMirrorToIncrementalDestination(
				new File("e:/data/perso/test2"));
	}

	/*
	 * public static FileNode genereArbre(File r) { if (r == null || (r != null
	 * && !r.exists()) || (r != null && !r.isDirectory())) {
	 * 
	 * } FileNode root = new FileNode(r); root.genererArbre(); return root; }
	 */

	/** @deprecated */
	public static void saveArbreNode(FileNode root, File jTreeFile)
			throws IOException {

		FileOutputStream fichier = new FileOutputStream(jTreeFile);
		ObjectOutputStream oos = new ObjectOutputStream(fichier);
		oos.writeObject(root);
		oos.flush();
		oos.close();
		fichier.close();

		if (Options.getInstance().isZipperJTree()) {
			ConversionFichier.zipper(jTreeFile, new File(jTreeFile.getPath()
					+ ".zip"));
			jTreeFile.delete();
		}
	}

	public static void persistJSaveJTree2File(JSaveTree jsjt)
			throws IOException {
		persistJSaveJTree2File(jsjt, jsjt.getFile4Saving());
	}

	public static void persistJSaveJTree2File(JSaveTree jsjt, File f)
			throws IOException {

		jsjt.setGeneratedDate(System.currentTimeMillis());
		log.info("Ecriture du fichier " + f.getPath());
		FileOutputStream fichier = new FileOutputStream(f);
		ObjectOutputStream oos = new ObjectOutputStream(fichier);
		oos.writeObject(jsjt);
		oos.flush();
		oos.close();
		fichier.close();

		if (Options.getInstance().isZipperJTree()) {
			log.info("Zip du fichier " + f.getPath());
			ConversionFichier.zipper(f, new File(f.getPath() + ".zip"));
			f.delete();
		}
	}

	public static void generateJTree4Incremental(File incPath)
			throws IOException {

		File[] dirInc = incPath.listFiles(new DirectoryFilter());
		if (dirInc.length == 0) {
			log.error("Il n'y a pas de repertoire incremental");
			return;
		}
		if (dirInc.length > 1) {
			log.error("Il y a plusieurs repertoires incrementals");
			return;
		}

		log.info("Generation du JTree pour " + dirInc[0].getPath()
				+ " (peut prendre plusieurs minutes)");
		FileNode root = new FileNode(dirInc[0]);
		File jTreeFile = new File(incPath.getPath() + File.separator
				+ ".jsaveTree_" + System.currentTimeMillis());
		log.info("Creation du fichier " + jTreeFile.getPath());
		JSaveServices.saveArbreNode(root, jTreeFile);
	}

	public static void generateJTree(File path) throws IOException {

		log.info("Generation du JTree pour " + path.getPath()
				+ " (peut prendre plusieurs minutes)...");
		FileNode root = new FileNode(path);

		JSaveServices.persistJSaveJTree2File(new JSaveTree(path, root));
	}

	/** @deprecated */
	public static FileNode getJTreeInIncremental(File incrementalPath)
			throws IOException, JSaveException, ClassNotFoundException {

		File[] files = incrementalPath.listFiles(new JSaveJTreeFilter());
		File jTreeFile = null;
		long plusRecent = 0;
		if (files.length == 0) {
			throw new JSaveException(
					"Pas de fichier jTree trouve dans le repertoire "
							+ incrementalPath.getPath());
		} else if (files.length == 1) {
			jTreeFile = files[0];
		} else {
			/*
			 * throw new JSaveException(
			 * "Plusieurs fichiers jTree trouves dans le repertoire " +
			 * incrementalPath.getPath());
			 */

			for (int i = 0; i < files.length; i++) {
				String datetime = files[i].getName().replaceFirst(
						".jsaveTree_", "").replaceFirst(".zip", "");
				if (Long.parseLong(datetime) > plusRecent) {
					plusRecent = Long.parseLong(datetime);
					jTreeFile = files[i];
				}
			}
		}

		// DeZipper si besoin
		if (jTreeFile.getName().endsWith(".zip")) {
			File dezipFile = new File(jTreeFile.getParent() + File.separator
					+ jTreeFile.getName().replaceFirst(".zip", ""));
			ConversionFichier.deZipper(jTreeFile, dezipFile);
			jTreeFile = dezipFile;
		}

		FileInputStream fichier = new FileInputStream(jTreeFile);
		ObjectInputStream ois = new ObjectInputStream(fichier);
		FileNode fileNode = (FileNode) ois.readObject();
		ois.close();
		fichier.close();

		return fileNode;
	}

	public static JSaveTree getJSaveTreeFromFile(File jSaveTreeFile)
			throws IOException, JSaveException, ClassNotFoundException {

		// DeZipper si besoin
		if (jSaveTreeFile.getName().endsWith(".zip")) {
			File dezipFile = new File(jSaveTreeFile.getParent()
					+ File.separator
					+ jSaveTreeFile.getName().replaceFirst(".zip", ""));
			ConversionFichier.deZipper(jSaveTreeFile, dezipFile);
			jSaveTreeFile = dezipFile;
		}

		FileInputStream fichier = new FileInputStream(jSaveTreeFile);
		ObjectInputStream ois = new ObjectInputStream(fichier);
		JSaveTree jSaveTree = (JSaveTree) ois.readObject();
		ois.close();
		fichier.close();

		return jSaveTree;
	}

	public static File getJSaveTreeFileFromPath(File path) throws IOException,
			JSaveException, ClassNotFoundException {

		File[] files = path.listFiles(new JSaveJTreeFilter());
		File jTreeFile = null;
		long plusRecent = 0;
		if (files.length == 0) {
			return null;
		} else if (files.length == 1) {
			jTreeFile = files[0];
		} else {
			for (int i = 0; i < files.length; i++) {
				String datetime = files[i].getName().replaceFirst(
						".jsaveTree_", "").replaceFirst(".zip", "");
				if (Long.parseLong(datetime) > plusRecent) {
					plusRecent = Long.parseLong(datetime);
					jTreeFile = files[i];
				}
			}
		}
		
		return jTreeFile; 
	}

	public static File createSubDirectory4Inc(File incPath)
			throws JSaveException {
		File dir = new File(incPath.getPath() + File.separator
				+ incPath.getName() + "_"
				+ ConversionDate.formatYYYYMMDD_HHMMSS2());
		dir.mkdir();
		if (!dir.exists() || !dir.isDirectory()) {
			throw new JSaveException("Impossible de creer le repertoire "
					+ dir.getPath());
		}
		log.info("Creation du repertoire " + dir.getPath());
		return dir;
	}
}
